/** 属性键 可以直接赋值的 */
enum Edom_attr_assign {
    innerText = 'innerText',
    innerHTML = 'innerHTML',
    textContent = 'textContent',

    // HTMLElement子类特有的属性
    disabled = 'disabled',
    readOnly = 'readOnly',
};
type Tdom_attr_key_assign = TEnumKeys<typeof Edom_attr_assign>;

/** 属性键 样式 */
enum Edom_attr_class {
    className = 'className',
};
type Tdom_attr_key_class = TEnumKeys<typeof Edom_attr_class>;

/** 属性键 样式列表 */
enum Edom_attr_classlist {
    classList = 'classList',
};
type Tdom_attr_key_classlist = TEnumKeys<typeof Edom_attr_classlist>;

/** 属性键 需要使用set方法的 */
enum Edom_attr_set {
    id = 'id',
    name = 'name',
    value = 'value',
    type = 'type',
    for = 'for',
};
type Tdom_attr_key_set = TEnumKeys<typeof Edom_attr_set>;

/** 属性键 只读属性 */
// TODO 使用Readonly推导出来
type Tdom_attr_key_readonlys = 'ATTRIBUTE_NODE'
    | 'CDATA_SECTION_NODE'
    | 'COMMENT_NODE'
    | 'DOCUMENT_FRAGMENT_NODE'
    | 'DOCUMENT_NODE'
    | 'DOCUMENT_POSITION_CONTAINED_BY'
    | 'DOCUMENT_POSITION_CONTAINS'
    | 'DOCUMENT_POSITION_DISCONNECTED'
    | 'DOCUMENT_POSITION_FOLLOWING'
    | 'DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC'
    | 'DOCUMENT_POSITION_PRECEDING'
    | 'DOCUMENT_TYPE_NODE'
    | 'ELEMENT_NODE'
    | 'ENTITY_NODE'
    | 'ENTITY_REFERENCE_NODE'
    | 'NOTATION_NODE'
    | 'PROCESSING_INSTRUCTION_NODE'
    | 'TEXT_NODE'
    | 'accessKeyLabel'
    | 'assignedSlot'
    | 'attributeStyleMap'
    | 'attributes'
    | 'baseURI'
    | 'childElementCount'
    | 'childNodes'
    | 'children'
    | 'clientHeight'
    | 'clientLeft'
    | 'clientTop'
    | 'clientWidth'
    | 'dataset'
    | 'firstChild'
    | 'firstElementChild'
    | 'lastChild'
    | 'lastElementChild'
    | 'localName'
    | 'namespaceURI'
    | 'nextElementSibling'
    | 'nextSibling'
    | 'nodeName'
    | 'nodeType'
    | 'offsetHeight'
    | 'offsetLeft'
    | 'offsetParent'
    | 'offsetTop'
    | 'offsetWidth'
    | 'ownerDocument'
    | 'parentElement'
    | 'parentNode'
    | 'part'
    | 'prefix'
    | 'previousElementSibling'
    | 'previousSibling'
    | 'scrollHeight'
    | 'scrollWidth'
    | 'shadowRoot'
    | 'style'
    | 'tagName';

// TODO HTMLElement子类特有的属性
/** 属性键 */
type Tdom_attr_keys = TExcludeUnion<keyof HTMLElement, Tdom_attr_key_readonlys> | Tdom_attr_key_assign | Tdom_attr_key_class | Tdom_attr_key_classlist | Tdom_attr_key_set;
/** 属性值 */
type Tdom_attr_value = Tvalue;
/** 属性配置对象 */
type Tdom_attr_obj = Partial<{ [key in Tdom_attr_keys]: Tdom_attr_value; }>;

interface KHTMLElement {
    /**
     * 设置属性
     * @param attrs 属性对象
     */
    setAttr(attrs: Tdom_attr_obj): KHTMLElement;
    /**
     * 设置属性
     * @param key 属性键
     * @param value 属性值 undefined: 无操作; null: 删除属性; others: 设置属性;
     */
    setAttr(key: Tdom_attr_keys, value: Tdom_attr_value): KHTMLElement;
}
{
    Object.defineProperty(KHTMLElement.prototype, 'setAttr', {
        writable: false,
        configurable: false,
        enumerable: false,
        value: U.F.overloading('DOM-setAttr',
            {
                types: [Etype.obj],
                fn: function (this: KHTMLElement, attrs: any) {
                    for (const key in attrs) {
                        this.setAttr(key as Tdom_attr_keys, attrs[key]);
                    }
                    return this;
                }
            },
            {
                types: [Etype.string, [Etype.string, Etype.boolean, Etype.number]],
                fn: function (this: KHTMLElement, key: string, value: string) {
                    if (U.O.hasKey(Edom_attr_assign, key)) {
                        this.elements.forEach(ele => { (ele as any)[key] = value; });
                        return this;
                    }

                    if (U.O.hasKey(Edom_attr_class, key)) {
                        return this.addClass(value);
                    }

                    if (U.O.hasKey(Edom_attr_classlist, key)) {
                        if (value.includes(',')) {
                            const values = value.split(',');
                            for (let i = 0; i < values.length; i++) {
                                const cls = values[i];
                                if (U.S.isEmpty(cls)) { continue; }
                                this.addClass(cls);
                            }
                        } else {
                            this.addClass(value);
                        }
                        return this;
                    }

                    this.elements.forEach(ele => { ele.setAttribute(key, value); });
                    return this;
                }
            },
            {
                types: [Etype.string, Etype.null],
                fn: function (this: KHTMLElement, key: string, value: null) {
                    if (U.O.hasKey(Edom_attr_assign, key)) {
                        this.elements.forEach(ele => { (ele as any)[key] = ''; });
                        return this;
                    }

                    if (U.O.hasKey(Edom_attr_class, key)) {
                        return this.removeClass(new RegExp('.*'));
                    }

                    if (U.O.hasKey(Edom_attr_classlist, key)) {
                        return this.removeClass(new RegExp('.*'));
                    }

                    this.elements.forEach(ele => { ele.removeAttribute(key); });
                    return this;
                }
            },
            {
                types: [Etype.string, Etype.undefined],
                fn: U.F.fn.this
            },
        )
    });
}
